/**
 * ReportGear(2011)
 */
package com.reportgear.designer.gui.controlpane;

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JToolBar;
import javax.swing.ListCellRenderer;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import net.abbp.swing.util.GuiUtils;
import net.abbp.swing.util.ImageUtils;

import com.reportgear.core.api.BaseObject;
import com.reportgear.core.api.Nameable;
import com.reportgear.core.swing.pane.base.EditorPane;
import com.reportgear.core.swing.pane.base.JBasePane;
import com.reportgear.designer.action.UpdateAction;
import com.reportgear.designer.gui.component.list.JNameEditList;
import com.reportgear.designer.gui.component.list.ModifyNameActionListener;
import com.reportgear.designer.gui.config.MenuDef;
import com.reportgear.designer.gui.config.ShortCut;
import com.reportgear.designer.gui.config.ToolBarDef;
import com.reportgear.report.core.api.compare.ComparatorUtils;

/**
 * 控制面板
 * 
 * @version 1.0 2011-4-25
 * @author <a herf="lexloo@gmail.com">lexloo</a>
 * @since Report 1.0
 */
public abstract class JControlPane<T extends Nameable> extends JBasePane {
	private static final long serialVersionUID = -3476562099307925155L;
	private ControlPaneShortCut[] shortCuts;
	private Map<Class<T>, NameableCreator<T>> creatorsMap;
	private JNameEditList nameableList;
	protected JControlUpdatePane controlUpdatePane;
	private ToolBarDef toolbarDef;
	private JToolBar toolBar;
	private JSplitPane mainSplitPane;
	private CardLayout cardLayout;
	private JPanel cardPane;
	private boolean isCreateUnrepeatedName = true;

	public JControlPane() {
		initComponentPane();
	}

	private void initComponentPane() {
		this.setLayout(new BorderLayout());
		this.controlUpdatePane = new JControlUpdatePane(createNameableCreators());

		JPanel pane = new JPanel();
		pane.setLayout(new BorderLayout());
		this.nameableList = new JNameEditList(new DefaultListModel());
		pane.add(new JScrollPane(this.nameableList), BorderLayout.CENTER);
		this.nameableList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

		this.nameableList.addMouseListener(new MouseAdapter() {
			public void mouseReleased(MouseEvent evt) {
				nameableList.stopEditing();

				if ((evt.getClickCount() >= 2) && (SwingUtilities.isLeftMouseButton(evt))) {
					nameableList.editItemAt(nameableList.getSelectedIndex());
				}

				if (!(SwingUtilities.isRightMouseButton(evt))) {
					return;
				}

				JControlPane.this.checkButtonEnabled();
				JPopupMenu menu = new JPopupMenu();
				for (ControlPaneShortCut shortcut : JControlPane.this.shortCuts) {
					shortcut.getShortCut().intoJPopupMenu(menu);
				}

				GuiUtils.showPopupMenu(menu, JControlPane.this.nameableList, evt.getX() - 1, evt.getY() - 1);
			}
		});

		this.nameableList.addListSelectionListener(new ListSelectionListener() {
			public void valueChanged(ListSelectionEvent evt) {
				controlUpdatePane.update();
				refreshCurrentUpdatePane();
				checkButtonEnabled();
			}
		});

		this.toolbarDef = new ToolBarDef();
		this.shortCuts = createShortCuts();
		for (ControlPaneShortCut shortCut : this.shortCuts) {
			this.toolbarDef.addShortCut(shortCut.getShortCut());
		}

		this.toolBar = ToolBarDef.createJToolBar();
		this.toolbarDef.updateToolBar(this.toolBar);
		pane.add(this.toolBar, BorderLayout.NORTH);

		this.cardLayout = new CardLayout();
		this.cardPane = new JPanel();
		this.cardPane.setLayout(this.cardLayout);

		JLabel select = new JLabel();
		this.cardPane.add(select, "SELECT");
		this.cardPane.add(this.controlUpdatePane, "EDIT");

		this.mainSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, pane, this.cardPane);
		this.mainSplitPane.setBorder(BorderFactory.createLineBorder(GuiUtils.getTitleLineBorderColor()));
		add(this.mainSplitPane, BorderLayout.CENTER);
		this.mainSplitPane.setDividerLocation(pane.getMinimumSize().width);
		this.cardPane.setMinimumSize(new Dimension(0, 0));

		checkButtonEnabled();
	}

	/**
	 * 创建可命名对象创建者Map
	 * 
	 * @return 可命名对象创建者Map
	 */
	public abstract Map<Class<T>, NameableCreator<T>> createNameableCreators();

	private ControlPaneShortCut[] createShortCuts() {
		return new ControlPaneShortCut[] { addItemShortCut(), removeItemShortCut(), copyItemShortCut(),
				moveUpItemShortCut(), moveDownItemShortCut(), sortItemShortCut() };
	}

	/**
	 * 新增操作
	 * 
	 * @return 新增操作
	 */
	protected ControlPaneShortCut addItemShortCut() {
		ShortCut shortCut;
		if (this.creatorsMap == null) {
			this.creatorsMap = createNameableCreators();
		}

		if (this.creatorsMap.size() == 1) {
			shortCut = new AddItemUpdateAction();
		} else {
			shortCut = new AddItemMenuDef(this.creatorsMap);
		}

		return (new AbsoluteEnableShortCut(shortCut));
	}

	private ControlPaneShortCut removeItemShortCut() {
		return new NormalEnableShortCut(new RemoveItemAction());
	}

	private ControlPaneShortCut copyItemShortCut() {
		return new NormalEnableShortCut(new CopyItemAction());
	}

	private ControlPaneShortCut moveUpItemShortCut() {
		return new MoveUpEnableShortCut(new MoveUpItemAction());
	}

	private ControlPaneShortCut moveDownItemShortCut() {
		return new MoveDownEnableShortCut(new MoveDownItemAction());
	}

	private ControlPaneShortCut sortItemShortCut() {
		return new SortEnableShortCut(new SortItemAction());
	}

	/**
	 * 获取选择列表大小
	 * 
	 * @return 选择列表大小
	 */
	public int getListSize() {
		return this.nameableList.getModel().getSize();
	}

	/**
	 * 获取列表中指定索引的元素
	 * 
	 * @param index
	 *            索引
	 * @return 索引中选定的元素
	 */
	public String getListElement(int index) {
		return this.nameableList.getNameAt(index);
	}

	/**
	 * 设置列表选择索引
	 * 
	 * @param index
	 *            索引
	 */
	public void setListSelectedIndex(int index) {
		this.nameableList.setSelectedIndex(index);
	}

	/**
	 * 设置列表单元编辑器
	 * 
	 * @param cellRender
	 *            单元编辑器
	 */
	public void setCellRenderer(ListCellRenderer cellRender) {
		this.nameableList.setCellRenderer(cellRender);
	}

	/**
	 * 设置列表是否可编辑
	 * 
	 * @param editable
	 *            是否可编辑
	 */
	public void setNameListEditable(boolean editable) {
		this.nameableList.setEditable(editable);
	}

	/**
	 * 列表是否可编辑
	 * 
	 * @return 是否可编辑
	 */
	public boolean isNameListEditable() {
		return this.nameableList.isEditable();
	}

	/**
	 * 是否创建不可重复的名称
	 * 
	 * @return 是否名称不可重复
	 */
	public boolean isCreateUnrepeatedName() {
		return this.isCreateUnrepeatedName;
	}

	/**
	 * 设置创建时名称是否不可重复
	 * 
	 * @param unrepeated
	 *            名称是否不可重复
	 */
	public void setCreateUnrepeatedName(boolean unrepeated) {
		this.isCreateUnrepeatedName = unrepeated;
	}

	/**
	 * 添加工具条快捷方式
	 * 
	 * @param shortCut
	 *            工具条快捷方式
	 */
	public void addToolBarAction(ShortCut shortCut) {
		this.toolbarDef.addShortCut(shortCut);
	}

	/**
	 * 更新面板
	 * 
	 * @return 面板值
	 */
	@SuppressWarnings("unchecked")
	public List<T> update() {
		this.controlUpdatePane.update();

		List<T> result = new ArrayList<T>();
		DefaultListModel listModel = (DefaultListModel) this.nameableList.getModel();

		for (int i = 0, size = listModel.getSize(); i < size; i++) {
			result.add((T) listModel.getElementAt(i));
		}

		return result;
	}

	/**
	 * 填充面板
	 */
	public void populate(List<T> values) {
		DefaultListModel listModel = (DefaultListModel) this.nameableList.getModel();
		listModel.removeAllElements();
		if ((values == null) || (values.isEmpty())) {
			return;
		}

		for (T v : values) {
			listModel.addElement(v);
		}

		if (!listModel.isEmpty()) {
			this.nameableList.setSelectedIndex(0);
		}

		checkButtonEnabled();
	}

	/**
	 * 添加名称修改监听器
	 * 
	 * @param listener
	 *            监听器
	 */
	public void addModifyNameActionListener(ModifyNameActionListener listener) {
		this.nameableList.addModifyNameActionListener(listener);
	}

	/**
	 * 移除名称修改监听器
	 * 
	 * @param listener
	 *            监听器
	 */
	public void removeModifyNameActionListener(ModifyNameActionListener listener) {
		this.nameableList.removeModifyNameActionListener(listener);
	}

	/**
	 * 更新当前面板
	 */
	@SuppressWarnings("unchecked")
	public void refreshCurrentUpdatePane() {
		T value = (T) this.nameableList.getSelectedValue();

		if (value == null) {
			return;
		}

		this.controlUpdatePane.populate(value);
	}

	/**
	 * 设置选中名称
	 * 
	 * @param name
	 *            名称
	 */
	public void setSelectedName(String name) {
		DefaultListModel model = (DefaultListModel) this.nameableList.getModel();

		for (int i = 0, size = model.getSize(); i < size; i++) {
			Nameable nameObj = (Nameable) model.getElementAt(i);

			if (ComparatorUtils.equals(name, nameObj.getName())) {
				this.nameableList.setSelectedIndex(i);
				return;
			}
		}
	}

	/**
	 * @return 获取选中值
	 */
	public Nameable getSelectedValue() {
		return (Nameable) this.nameableList.getSelectedValue();
	}

	public void setJNameEdListHasIcon(boolean hasIcon) {
		if (this.nameableList == null) {
			return;
		}

		this.nameableList.setHasIcon(hasIcon);
	}

	/**
	 * 创建不重复的名称
	 * 
	 * @param prefix
	 *            名称前缀
	 * @return 不重复的名称
	 */
	protected String createUnrepeatedName(String prefix) {
		if (!(this.isCreateUnrepeatedName)) {
			return prefix;
		}

		DefaultListModel model = (DefaultListModel) this.nameableList.getModel();

		int pointer = model.getSize() + 1;
		String result = prefix + pointer;
		boolean isExist = false;
		while (true) {
			for (int i = 0, size = model.getSize(); i < size; i++) {
				Nameable nameObj = (Nameable) model.getElementAt(i);

				if (result.equals(nameObj.getName())) {
					result = prefix + (pointer++);
					isExist = true;
					break;
				}
			}

			if (!isExist) {
				break;
			}
		}

		return result;
	}

	/**
	 * 检查按钮的有效性
	 */
	private void checkButtonEnabled() {
		int i = this.nameableList.getSelectedIndex();
		if (i == -1) {
			this.cardLayout.show(this.cardPane, "SELECT");
		} else {
			this.cardLayout.show(this.cardPane, "EDIT");
		}
		for (ControlPaneShortCut shortCut : this.shortCuts)
			shortCut.checkEnable();
	}

	/**
	 * 获取第一个的快捷方式
	 * 
	 * @return 快捷方式
	 */
	public ShortCut getFirstShortCut() {
		return this.shortCuts[0].getShortCut();
	}

	/**
	 * 
	 * @return 第一个对象创建器
	 */
	public NameableCreator<T> getFirstNameableCreator() {
		if (this.creatorsMap.isEmpty()) {
			throw new InternalError("对象创建不能为空!");
		} else {
			return this.creatorsMap.values().iterator().next();
		}
	}

	// 更新面板
	@SuppressWarnings("serial")
	private class JControlUpdatePane extends EditorPane<T> {
		private CardLayout card;
		private JPanel cardPane;
		private Map<Class<T>, EditorPane<T>> updatePaneMap;

		public JControlUpdatePane(Map<Class<T>, NameableCreator<T>> creatorMap) {
			initUpdatePane(creatorMap);
		}

		private void initUpdatePane(Map<Class<T>, NameableCreator<T>> creatorMap) {
			if (creatorMap == null) {
				return;
			}

			this.card = new CardLayout();
			this.cardPane = new JPanel(this.card);
			setLayout(new BorderLayout());
			add(this.cardPane);

			this.updatePaneMap = new HashMap<Class<T>, EditorPane<T>>();
			for (Map.Entry<Class<T>, NameableCreator<T>> entry : creatorMap.entrySet()) {
				EditorPane<T> updatePane = entry.getValue().getUpdatePane();
				this.updatePaneMap.put(entry.getKey(), updatePane);
				this.cardPane.add(updatePane, entry.getKey().getName());
			}
		}

		public void populate(T value) {
			if (value == null) {
				return;
			}

			EditorPane<T> editorPane = this.updatePaneMap.get(value.getClass());
			if (editorPane != null) {
				editorPane.populate(value);
				this.card.show(this.cardPane, value.getClass().getName());
			} else {
				logger.warn("没有指定编辑器,编辑对象：" + value.getClass().getName());
			}
		}

		public T update() {
			for (EditorPane<T> editorPane : this.updatePaneMap.values()) {
				if (editorPane.isVisible()) {
					return editorPane.update();
				}
			}

			return null;
		}

		@Override
		public int showDialog(Component owner) {
			throw new UnsupportedOperationException();
		}
	}

	private class MoveDownEnableShortCut extends ControlPaneShortCut {
		public MoveDownEnableShortCut(ShortCut paramShortCut) {
			this.shortCut = paramShortCut;
		}

		public void checkEnable() {
			this.shortCut.setEnabled((JControlPane.this.nameableList.getModel().getSize() > 1)
					&& (JControlPane.this.nameableList.getSelectedIndex() < JControlPane.this.nameableList.getModel()
							.getSize() - 1));
		}
	}

	private class MoveUpEnableShortCut extends ControlPaneShortCut {
		public MoveUpEnableShortCut(ShortCut paramShortCut) {
			this.shortCut = paramShortCut;
		}

		public void checkEnable() {
			this.shortCut.setEnabled((JControlPane.this.nameableList.getModel().getSize() > 1)
					&& (JControlPane.this.nameableList.getSelectedIndex() > 0));
		}
	}

	private class SortEnableShortCut extends ControlPaneShortCut {
		public SortEnableShortCut(ShortCut paramShortCut) {
			this.shortCut = paramShortCut;
		}

		public void checkEnable() {
			this.shortCut.setEnabled(JControlPane.this.nameableList.getModel().getSize() > 1);
		}
	}

	private class NormalEnableShortCut extends ControlPaneShortCut {
		public NormalEnableShortCut(ShortCut shortCut) {
			this.shortCut = shortCut;
		}

		public void checkEnable() {
			this.shortCut.setEnabled((JControlPane.this.nameableList.getModel().getSize() > 0)
					&& (JControlPane.this.nameableList.getSelectedIndex() != -1));
		}
	}

	private class AbsoluteEnableShortCut extends ControlPaneShortCut {
		public AbsoluteEnableShortCut(ShortCut shortCut) {
			this.shortCut = shortCut;
		}

		public void checkEnable() {
			this.shortCut.setEnabled(true);
		}
	}

	// 排序
	private class SortItemAction extends UpdateAction {
		private boolean isAtoZ = false;

		public SortItemAction() {
			setName("排序");
			setMnemonic('S');
			setSmallIcon(ImageUtils.readIcon("control/sortAsc.png"));
		}

		public void actionPerformed(ActionEvent action) {
			Object selected = JControlPane.this.nameableList.getSelectedValue();
			DefaultListModel listModel = (DefaultListModel) JControlPane.this.nameableList.getModel();
			Nameable[] valueArr = new Nameable[listModel.getSize()];
			if (valueArr.length <= 0) {
				return;
			}

			for (int i = 0, size = listModel.getSize(); i < size; ++i) {
				valueArr[i] = ((Nameable) listModel.getElementAt(i));
			}

			Comparator<Nameable> comparator;
			if (this.isAtoZ) {
				comparator = new Comparator<Nameable>() {
					public int compare(Nameable name1, Nameable name2) {
						return (-ComparatorUtils.compare(name1.getName(), name2.getName()));
					}
				};
				this.isAtoZ = (!(this.isAtoZ));
				Arrays.sort(valueArr, comparator);
			} else {
				comparator = new Comparator<Nameable>() {
					public int compare(Nameable name1, Nameable name2) {
						return ComparatorUtils.compare(name1.getName(), name2.getName());
					}
				};
				this.isAtoZ = (!(this.isAtoZ));
				Arrays.sort(valueArr, comparator);
			}
			for (int i = 0, len = valueArr.length; i < len; ++i) {
				listModel.set(i, valueArr[i]);
			}

			if (selected != null) {
				nameableList.setSelectedValue(selected, true);
			}

			checkButtonEnabled();
			nameableList.repaint();
		}
	}

	// 下移
	private class MoveDownItemAction extends UpdateAction {
		public MoveDownItemAction() {
			setName("下移");
			setMnemonic('D');
			setSmallIcon(ImageUtils.readIcon("control/down.png"));
		}

		public void actionPerformed(ActionEvent evt) {
			int i = JControlPane.this.nameableList.getSelectedIndex();
			if (i == -1) {
				return;
			}

			if (i >= JControlPane.this.nameableList.getModel().getSize() - 1) {
				return;
			}

			DefaultListModel listModel = (DefaultListModel) JControlPane.this.nameableList.getModel();
			Object nextObj = listModel.get(i + 1);
			listModel.set(i + 1, listModel.get(i));
			listModel.set(i, nextObj);

			nameableList.setSelectedIndex(i + 1);
			nameableList.ensureIndexIsVisible(i + 1);
		}
	}

	// 上移
	private class MoveUpItemAction extends UpdateAction {
		public MoveUpItemAction() {
			setName("上移");
			setMnemonic('U');
			setSmallIcon(ImageUtils.readIcon("control/up.png"));
		}

		public void actionPerformed(ActionEvent evt) {
			int i = JControlPane.this.nameableList.getSelectedIndex();
			if (i <= 0) {
				return;
			}

			DefaultListModel listModel = (DefaultListModel) JControlPane.this.nameableList.getModel();
			Object prevObj = listModel.get(i - 1);
			listModel.set(i - 1, listModel.get(i));
			listModel.set(i, prevObj);

			nameableList.setSelectedIndex(i - 1);
			nameableList.ensureIndexIsVisible(i - 1);
		}
	}

	// 复制
	private class CopyItemAction extends UpdateAction {
		public CopyItemAction() {
			setName("复制");
			setMnemonic('C');
			setSmallIcon(ImageUtils.readIcon("control/copy.png"));
		}

		public void actionPerformed(ActionEvent action) {
			Object selected = JControlPane.this.nameableList.getSelectedValue();
			if (selected == null) {
				return;
			}

			JControlPane.this.controlUpdatePane.update();
			try {
				if (selected instanceof BaseObject) {

				}
				BaseObject cloned = ((BaseObject) selected).clone();
				if (cloned instanceof Nameable) {
					((Nameable) cloned).setName(((Nameable) selected).getName() + "复制");
				}

				int index = JControlPane.this.nameableList.getSelectedIndex();
				DefaultListModel listModel = (DefaultListModel) JControlPane.this.nameableList.getModel();
				listModel.add(index + 1, cloned);
				nameableList.setSelectedIndex(index + 1);
				nameableList.ensureIndexIsVisible(index + 1);
			} catch (Exception ex) {
				ex.printStackTrace();
			}
		}
	}

	// 移除
	private class RemoveItemAction extends UpdateAction {
		public RemoveItemAction() {
			setName("移除");
			setMnemonic('R');
			setSmallIcon(ImageUtils.readIcon("control/remove.png"));
		}

		public void actionPerformed(ActionEvent paramActionEvent) {
			try {
				JControlPane.this.nameableList.getCellEditor().stopCellEditing();
			} catch (Exception localException) {
			}

			if (!(GuiUtils.removeJListSelectedNodes(JControlPane.this.nameableList))) {
				return;
			}

			JControlPane.this.checkButtonEnabled();
		}
	}

	private class AddItemMenuDef extends MenuDef {
		public AddItemMenuDef(Map<Class<T>, NameableCreator<T>> creators) {
			setName("新增");
			setMnemonic('A');
			setIconPath("control/addPopup.png");
			wrapActionListener(creators);
		}

		private void wrapActionListener(Map<Class<T>, NameableCreator<T>> creators) {
			throw new UnsupportedOperationException();
			// for (final NameableCreator create : creators) {
			// addShortCut(new UpdateAction() {
			// public void actionPerformed(ActionEvent paramActionEvent) {
			// JNameEditList list = JControlPane.this.nameableList;
			// DefaultListModel listModel = (DefaultListModel) list.getModel();
			// Nameable nameable = create.createNameable();
			// if (nameable instanceof NameObject) {
			// if (StringUtils.isEmpty(nameable.getName()))
			// nameable.setName(JControlPane.this.createUnrepeatedName(create.namePrefix()));
			// else
			// nameable.setName(JControlPane.this.createUnrepeatedName(nameable.getName()));
			// } else {
			// nameable.setName(JControlPane.this.createUnrepeatedName(create.namePrefix()));
			// }
			//
			// listModel.addElement(nameable);
			// list.setSelectedIndex(listModel.getSize() - 1);
			// list.ensureIndexIsVisible(listModel.getSize() - 1);
			// list.editItemAt(list.getSelectedIndex());
			// }
			// });
			// }
		}
	}

	private class AddItemUpdateAction extends UpdateAction {
		private NameableCreator<T> creator;

		public AddItemUpdateAction() {
			creator = getFirstNameableCreator();

			setName("新增");
			setMnemonic('A');
			setSmallIcon(ImageUtils.readIcon("control/addPopup.png"));
		}

		public void actionPerformed(ActionEvent paramActionEvent) {
			JNameEditList nameEditList = JControlPane.this.nameableList;
			DefaultListModel listModel = (DefaultListModel) nameEditList.getModel();
			Nameable nameable = this.creator.createNameable();

			if (nameable.getName().equals("")) {
				nameable.setName(JControlPane.this.createUnrepeatedName(this.creator.namePrefix()));
			} else {
				nameable.setName(JControlPane.this.createUnrepeatedName(nameable.getName()));
			}

			listModel.addElement(nameable);
			nameEditList.setSelectedValue(nameable, true);
			nameEditList.editItemAt(nameEditList.getSelectedIndex());
		}
	}
}